package com.clp.protocol.iec104.connect.config;

import com.clp.protocol.core.common.config.CheckableConfig;
import com.clp.protocol.core.exception.ConnectionAlreadyExistException;
import com.clp.protocol.core.exception.LocalHostDoesNotExistException;
import com.clp.protocol.core.utils.LocalIpUtil;
import com.clp.protocol.core.utils.StringUtil;
import com.clp.protocol.iec104.client.Iec104Client;
import lombok.Getter;

/**
 * 连接配置
 */
@Getter
public abstract class ConnConfig implements CheckableConfig {
    /**
     * 默认本地ip
     */
    public static final String DEFAULT_LOCAL_HOST = LocalIpUtil.getLocalIpSet().iterator().next();
    /**
     * 默认本地端口号（0表示随机本地端口）
     */
    public static final int DEFAULT_LOCAL_PORT = 0;
    /**
     * 默认远程端口号
     */
    public static final int DEFAULT_REMOTE_PORT = 2404;
    /**
     * 默认公共地址
     */
    public static final int DEFAULT_RTU_ADDR = 1;
    /**
     * 默认最大累计确认数
     */
    public static final int DEFAULT_MAX_ACK_NUM = 8;

    /**
     * 默认T0时间，单位为秒
     */
    public static final int DEFAULT_T0 = 6; // 30
    /**
     * 默认T1时间，单位为秒
     */
    public static final int DEFAULT_T1 = 3; // 15
    /**
     * 默认T2时间，单位为秒
     */
    public static final int DEFAULT_T2 = 2; // 10
    /**
     * 默认T3时间，单位为秒
     */
    public static final int DEFAULT_T3 = 4; // 20

    /******************************************************************************************************************/

    private final String localHost;
    private final int localPort;
    private final String remoteHost;
    private final int remotePort;
    /**
     * 公共地址
     */
    protected final int rtuAddr;

    /**
     * T0 T1 T2 T3 时间设置
     */
    protected final int t0;
    protected final int t1;
    protected final int t2;
    protected final int t3;
    /**
     * 最大累计确认数
     */
    private final int maxAckNum;

    protected ConnConfig(Configurer<? extends Configurer<?>> configurer) {
        this.localHost = configurer.localHost;
        this.localPort = configurer.localPort;
        this.remoteHost = configurer.remoteHost;
        this.remotePort = configurer.remotePort;
        this.rtuAddr = configurer.rtuAddr;
        this.t0 = configurer.t0;
        this.t1 = configurer.t1;
        this.t2 = configurer.t2;
        this.t3 = configurer.t3;
        this.maxAckNum = configurer.maxAckNum;
    }

    protected static class Configurer<C extends Configurer<C>> {
        private String localHost = DEFAULT_LOCAL_HOST;
        private int localPort = DEFAULT_LOCAL_PORT;
        private String remoteHost;
        private int remotePort = DEFAULT_REMOTE_PORT;
        /**
         * 公共地址
         */
        protected int rtuAddr = DEFAULT_RTU_ADDR;

        /**
         * T0 T1 T2 T3 时间设置
         */
        protected int t0 = DEFAULT_T0;
        protected int t1 = DEFAULT_T1;
        protected int t2 = DEFAULT_T2;
        protected int t3 = DEFAULT_T3;
        /**
         * 最大累计确认数
         */
        private int maxAckNum = DEFAULT_MAX_ACK_NUM;

        @SuppressWarnings("unchecked")
        private C self() {
            return (C) this;
        }

        public C connection(String remoteHost, int remotePort) {
            return connection(DEFAULT_LOCAL_HOST, DEFAULT_LOCAL_PORT, remoteHost, remotePort);
        }

        public C connection(String localHost, int localPort, String remoteHost, int remotePort) {
            this.localHost = localHost;
            this.localPort = localPort;
            this.remoteHost = remoteHost;
            this.remotePort = remotePort;
            return self();
        }

        public C rtuAddr(int rtuAddr) {
            this.rtuAddr = rtuAddr;
            return self();
        }

        public C t0t1t2t3(int t0, int t1, int t2, int t3) {
            this.t0 = t0;
            this.t1 = t1;
            this.t2 = t2;
            this.t3 = t3;
            return self();
        }
    }

    @Override
    public void check() throws Throwable {
        // 检查 ip 是否合法，本地ip是否存在
        if (StringUtil.isBlank(localHost) || StringUtil.isBlank(remoteHost)) {
            throw new RuntimeException("非法的本地IP地址或远程IP地址！");
        }
        if (!LocalIpUtil.hasLocalHost(localHost)) {
            throw new LocalHostDoesNotExistException(localHost);
        }

        // 检查 从站ip 是否已经被使用
        if (Iec104Client.get().hasMaster(remoteHost, remotePort)) {
            throw new ConnectionAlreadyExistException(remoteHost, remotePort);
        }
    }
}
